package cn.spikego.advicelite.injector;

import cn.spikego.advicelite.agent.attacher.AgentAttacher;
import com.formdev.flatlaf.FlatLightLaf;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.File;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.List;

public class AdviceLiteInjector {

    public static void main(String[] args) {
        // 初始化 FlatLaf
        FlatLightLaf.setup();

        // 启动 GUI
        SwingUtilities.invokeLater(AdviceLiteInjector::createAndShowGUI);
}

    private static void createAndShowGUI() {
        // 创建主窗口
        JFrame frame = new JFrame("AdviceLite Injector");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(600, 400);
        frame.setLocationRelativeTo(null);

        // 设置图标
        ImageIcon icon = new ImageIcon(AdviceLiteInjector.class.getResource("/asstes/icon/AdviceLite.png"));
        frame.setIconImage(icon.getImage());

        // 主面板
        JPanel mainPanel = new JPanel(new BorderLayout());
        frame.add(mainPanel);

        // 标题标签
        JLabel titleLabel = new JLabel("Select a VM to attach:", SwingConstants.CENTER);
        titleLabel.setFont(new Font("Arial", Font.BOLD, 16));
        mainPanel.add(titleLabel, BorderLayout.NORTH);

        // 列表模型和列表组件
        DefaultListModel<String> listModel = new DefaultListModel<>();
        JList<String> vmList = new JList<>(listModel);
        vmList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        vmList.setVisibleRowCount(10);
        JScrollPane scrollPane = new JScrollPane(vmList);
        mainPanel.add(scrollPane, BorderLayout.CENTER);

        // 填充虚拟机列表
        List<VirtualMachineDescriptor> descriptors = VirtualMachine.list();
        int index = 0;
        for (VirtualMachineDescriptor descriptor : descriptors) {
            String displayName = descriptor.displayName().split(" ")[0];
            listModel.addElement("#" + (++index) + " > " + descriptor.id() + " " + displayName);
        }

        // 按钮面板
        JPanel buttonPanel = new JPanel();
        JButton attachButton = new JButton("Attach");
        JButton cancelButton = new JButton("Cancel");
        buttonPanel.add(attachButton);
        buttonPanel.add(cancelButton);
        mainPanel.add(buttonPanel, BorderLayout.SOUTH);

        // 取消按钮事件
        cancelButton.addActionListener(e -> System.exit(0));

        // 附加按钮事件
        attachButton.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int selectedIndex = vmList.getSelectedIndex();
                if (selectedIndex == -1) {
                    JOptionPane.showMessageDialog(frame, "Please select a VM!", "Error", JOptionPane.ERROR_MESSAGE);
                    return;
                }

                VirtualMachineDescriptor selectedVM = descriptors.get(selectedIndex);
                String agentPath = getAgentJarPath();

                try {
                    AgentAttacher.attachDynamic(agentPath, selectedVM.id());
                    JOptionPane.showMessageDialog(frame, "Attached successfully!", "Success", JOptionPane.INFORMATION_MESSAGE);
                } catch (Exception ex) {
                    ex.printStackTrace();
                    String errorMsg = ex.getMessage();
                    if (errorMsg != null && errorMsg.contains("UnsupportedClassVersionError")) {
                        JOptionPane.showMessageDialog(frame, 
                            "Java version mismatch!\n\n" +
                            "This agent requires Java 17+, but the target Minecraft is running on an older Java version.\n\n" +
                            "For Minecraft 1.8.9: Please use Java 17+ to run Minecraft\n" +
                            "For Minecraft 1.18+: Should work with Java 17+\n\n" +
                            "Original error: " + errorMsg, 
                            "Java Version Error", JOptionPane.ERROR_MESSAGE);
                    } else {
                        JOptionPane.showMessageDialog(frame, "Failed to attach: " + errorMsg, "Error", JOptionPane.ERROR_MESSAGE);
                    }
                }
            }
        });

        // 显示窗口
        frame.setVisible(true);
    }

    private static String getAgentJarPath() {
        try {
            String path = AdviceLiteInjector.class.getProtectionDomain().getCodeSource().getLocation().getPath();
            path = URLDecoder.decode(path, StandardCharsets.UTF_8.name());
            
            // Convert to Windows path format
            if (path.startsWith("/") && System.getProperty("os.name").toLowerCase().contains("windows")) {
                path = path.substring(1);
            }
            path = path.replace("/", "\\");
            
            // If it's a classes directory, look for the JAR file
            File file = new File(path);
            if (file.isDirectory() && path.contains("classes")) {
                // Look for JAR in build/libs directory
                String projectRoot = path.substring(0, path.indexOf("build"));
                File libsDir = new File(projectRoot + "build\\libs");
                if (libsDir.exists()) {
                    // First try to find shadowJar (fat jar with -all suffix)
                    File[] allJars = libsDir.listFiles((dir, name) -> name.endsWith("-all.jar"));
                    if (allJars != null && allJars.length > 0) {
                        return allJars[0].getAbsolutePath();
                    }
                    
                    // Fallback to any JAR file
                    File[] jars = libsDir.listFiles((dir, name) -> 
                        name.endsWith(".jar") && !name.contains("-sources") && !name.contains("-javadoc"));
                    if (jars != null && jars.length > 0) {
                        return jars[0].getAbsolutePath();
                    }
                }
            }
            
            return path;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}